﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Modules.Audit;
using Modules.Payroll.Repositories;
using Modules.Project.Entitys;
using Modules.Project.Repositories;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Exceptions;
using System.Net.Mail;
using static Modules.Audit.SysAuditLogConstants;
using static Modules.Payroll.PayrollConstants;
using static Modules.Project.ProjectConstants;
using static Modules.System.Flow.FlowConstants;

namespace Modules.Project
{
    [UseDI(ServiceLifetime.Scoped)]
    public class ProjectLockOutService
    {
        private readonly ProjectLockOutRepository projectLockOutRepository;
        private readonly IApplicationContext applicationContext;
        private readonly SysAuditLogService sysAuditLogService;
        private readonly ProjectService projectService;
        private readonly ILogger logger;
        private readonly ProjectAttachmentService projectAttachmentService;
        private readonly ProjectStatusChangeRecordService projectStatusChangeRecordService;

        public ProjectLockOutService(ProjectLockOutRepository projectLockOutRepository, IApplicationContext applicationContext, SysAuditLogService sysAuditLogService, ProjectService projectService, ILogger<ProjectLockOutService> logger, ProjectAttachmentService projectAttachmentService, ProjectStatusChangeRecordService projectStatusChangeRecordService)
        {
            this.projectLockOutRepository = projectLockOutRepository;
            this.applicationContext = applicationContext;
            this.sysAuditLogService = sysAuditLogService;
            this.projectService = projectService;
            this.logger = logger;
            this.projectAttachmentService = projectAttachmentService;
            this.projectStatusChangeRecordService = projectStatusChangeRecordService;
        }

        public IPagedList<ProjectLockOut> GetProjectLockOuts(ProjectLockOutQuery query, int pageIndex, int pageSize)
        {
            return projectLockOutRepository.GetProjectLockOuts(query, pageIndex, pageSize);
        }

        public IEnumerable<ProjectLockOut> GetProjectLockOutsByProjectId(int projectId)
        {
            return projectLockOutRepository.GetProjectLockOutsByProjectId(projectId);
        }

        public void Deleted(IEnumerable<int> ids)
        {
            foreach (var id in ids)
            {
                Delete(id);
            }
        }

        public ProjectLockOut? Get(int id)
        {
            return projectLockOutRepository.Get(id);
        }

        public void Delete(int id)
        {
            projectLockOutRepository.DeleteByEntityId(id);
        }

        /// <summary>
        /// 审核
        /// </summary>
        /// <param name="id">停工记录id</param>
        /// <param name="auditIdea">审核意见</param>
        /// <param name="AuditIdeaContent">意见描述</param>
        /// <param name="personFlowEngine">流程步骤</param>
        /// <exception cref="BusinessException"></exception>
        public void Audit(int id, AuditIdea auditIdea, string? AuditIdeaContent, FlowEngine personFlowEngine)
        {
            try
            {
                ProjectLockOut? projectLockOut = projectLockOutRepository.Get(id);
                if (projectLockOut == null)
                    throw new BusinessException("项目停工信息不存在");
                SysAuditLog sysAuditLog = new SysAuditLog()
                {
                    ObjectId = id,
                    AuditIdea = auditIdea,
                    AuditIdeaContent = AuditIdeaContent,
                    TableName = "project_lock_out"
                };
                applicationContext.Transaction.Begin();//开始事务
                bool isFirst = false;
                FlowEngine? flowEngineCode = sysAuditLogService.Audit(out isFirst, projectLockOut.FlowEngineCode.Value, sysAuditLog, personFlowEngine);
                if (isFirst)
                    projectLockOut.AuditType = 审核类型.待提交;
                if (flowEngineCode == FlowEngine.结束)
                {
                    projectLockOut.AuditType = 审核类型.已完结;
                    projectLockOut.AuditStatus = 审核状态.成功;
                    projectLockOut.FlowEngineCode = FlowEngine.结束;
                    if (projectLockOut.PlanStartDate?.Date <= DateTime.Now.Date)
                    {
                        Lock(projectLockOut);
                    }
                }
                projectLockOut.FlowEngineCode = flowEngineCode.Value;
                projectLockOutRepository.Update(projectLockOut);
                applicationContext.Transaction.Complete();//完成事务
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"CorpAudit Exception id:{id}");
                throw new BusinessException($"当前信息您暂时不能审核");
            }
        }

        /// <summary>
        /// 提交审核
        /// </summary>
        /// <param name="data">停工记录主数据</param>
        /// <param name="flowCode">流程编码 建议使用常量 FlowConstants</param>
        /// <exception cref="BusinessException"></exception>
        public void SubmitAudit(ProjectLockOut data, string flowCode)
        {
            FlowEngine flowEngine = sysAuditLogService.SubmitAuditLog(data.Id, flowCode, "project_lock_out");
            data.FlowEngineCode = flowEngine;
            projectLockOutRepository.Update(data);
        }

        public void Create(ProjectLockOut entity, IEnumerable<string> attachments)
        {
            //查询当前项目最后一条数据
            //ProjectLockOut? projectLockOut = GetProjectLockOutsByProjectId(entity.ProjectId).OrderByDescending(a => a.CreateTime).FirstOrDefault(a => a.AuditType != 审核类型.已完结);
            ProjectLockOut? projectLockOut = GetProjectLockOutsByProjectId(entity.ProjectId).OrderByDescending(a => a.CreateTime).FirstOrDefault();
            if (projectLockOut != null)
            {
                if (projectLockOut.Status == entity.Status)
                    throw new BusinessException($"不允许重复申请当前项目{entity.Status.GetDescription}记录");
            }

            ProjectInfo? projectInfo = projectService.GetProjectInfo(entity.ProjectId);
            if (projectInfo == null)
            {
                throw new BusinessException("项目信息不存在");
            }
            //if (projectInfo.PrjStatus == 项目状态.停工)
            try
            {
                //开始事务
                applicationContext.Transaction.Begin();
                if (entity.Status == 停复工申请状态.停工)
                {
                    if (projectInfo.PrjStatus == 项目状态.停工)
                        throw new BusinessException("当前项目已经申请停工，不能重复申请");

                    #region 1、增加一条停工数据

                    entity.JobStatus = 0;
                    entity.AuditStatus = 审核状态.无;
                    entity.AuditType = 审核类型.待提交;
                    entity.CreateTime = DateTime.Now;
                    projectLockOutRepository.Insert(entity);

                    #endregion 1、增加一条停工数据

                    #region 2、增加一条提交审批记录

                    if (entity.PlanEndDate.HasValue && entity.PlanStartDate.HasValue)
                    {
                        if (projectInfo.IndustryType == 行业主管部门.住建) entity.FlowCode = 停复工申请流程_住建;
                        else entity.FlowCode = 停复工申请流程;

                        //if ((entity.PlanEndDate.Value - entity.PlanStartDate.Value).Days > 90) {
                        //    if (projectInfo.IndustryType == 行业主管部门.住建) entity.FlowCode = 已超过3个月停复工申请流程_住建;
                        //    else entity.FlowCode = 已超过3个月停复工申请流程;

                        //}
                        //else {
                        //    if (projectInfo.IndustryType == 行业主管部门.住建) entity.FlowCode = 未超过3个月停复工申请流程_住建;
                        //    else entity.FlowCode = 未超过3个月停复工申请流程;
                        //}
                    }
                    else throw new BusinessException("计划停工日期或计划复工日期不能为空");
                    entity.AuditType = 审核类型.待审核;
                    SubmitAudit(entity, entity.FlowCode);

                    #endregion 2、增加一条提交审批记录
                }
                else if (entity.Status == 停复工申请状态.复工)
                {
                    if (projectInfo.PrjStatus == 项目状态.在建)
                        throw new BusinessException("当前项目已经是在建，不能重复申请");
                    Out(entity);
                }

                #region 附件

                var attachmentIds = projectAttachmentService.GetProjectAttachmentsByObjectIdAndType(entity.Id, 附件类型.停复工附件, 项目附件租户.LockOut).Select(a => a.Id);
                projectAttachmentService.Deleted(attachmentIds);

                foreach (var item in attachments)
                {
                    ProjectAttachment attachment = new()
                    {
                        Id = Guid.NewGuid().ToString().Replace("-", ""),
                        AttachmentId = item,
                        ObjectId = entity.Id.ToString(),
                        AttachmentType = 附件类型.停复工附件,
                        CreateTime = DateTime.Now,
                        Tenant = 项目附件租户.LockOut
                    };
                    projectAttachmentService.Create(attachment);
                }

                #endregion 附件

                applicationContext.Transaction.Complete();//提交事务
            }
            catch (BusinessException ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"停复工申请失败");
                throw new BusinessException(ex.Message);
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"停复工申请失败");
                throw new BusinessException("停复工申请失败");
            }
        }

        public IEnumerable<ProjectLockOut> GetProjectLockOutsByStatus(停复工申请状态 status)
        {
            return projectLockOutRepository.GetProjectLockOutsByStatus(status);
        }

        /// <summary>
        /// 停工
        /// </summary>
        /// <param name="entity"></param>
        public void Lock(ProjectLockOut entity)
        {
            #region 1、将项目状态改为停工

            projectService.UpdateProjectStatus(entity.ProjectId, 项目状态.停工, entity.PlanStartDate);

            #endregion 1、将项目状态改为停工

            #region 2、将当前停工信息job_status据改为 已执行  JobRunTime更改为当前时间

            entity.StartDate = DateTime.Now.Date;
            entity.JobRunTime = DateTime.Now;
            entity.JobStatus = 1;
            projectLockOutRepository.Update(entity);

            #endregion 2、将当前停工信息job_status据改为 已执行  JobRunTime更改为当前时间
        }

        /// <summary>
        /// 修改停复工（重新走审核流程）
        /// </summary>
        /// <param name="entity"></param>
        public void UpdateProjectLockOut(ProjectLockOut entity, IEnumerable<string> attachments)
        {
            ProjectInfo? projectInfo = projectService.GetProjectInfo(entity.ProjectId);
            if (projectInfo == null)
            {
                throw new BusinessException("项目信息不存在");
            }
            //if (projectInfo.PrjStatus == 项目状态.停工)
            try
            {
                //开始事务
                applicationContext.Transaction.Begin();
                if (entity.Status == 停复工申请状态.停工)
                {
                    if (projectInfo.PrjStatus == 项目状态.停工)
                        throw new BusinessException("当前项目已经申请停工，不能重复申请");

                    #region 1、修改停复工数据

                    entity.JobStatus = 0;
                    entity.AuditStatus = 审核状态.无;
                    entity.AuditType = 审核类型.待提交;
                    projectLockOutRepository.Update(entity);

                    #endregion 1、修改停复工数据

                    #region 2、增加一条提交审批记录

                    if (entity.PlanEndDate.HasValue && entity.PlanStartDate.HasValue)
                    {
                        if (projectInfo.IndustryType == 行业主管部门.住建) entity.FlowCode = 停复工申请流程_住建;
                        else entity.FlowCode = 停复工申请流程;

                        //if ((entity.PlanEndDate.Value - entity.PlanStartDate.Value).Days > 90) {
                        //    if (projectInfo.IndustryType == 行业主管部门.住建) entity.FlowCode = 已超过3个月停复工申请流程_住建;
                        //    else entity.FlowCode = 已超过3个月停复工申请流程;

                        //}
                        //else {
                        //    if (projectInfo.IndustryType == 行业主管部门.住建) entity.FlowCode = 未超过3个月停复工申请流程_住建;
                        //    else entity.FlowCode = 未超过3个月停复工申请流程;
                        //}
                    }
                    else throw new BusinessException("计划停工日期或计划复工日期不能为空");
                    entity.AuditType = 审核类型.待审核;
                    SubmitAudit(entity, entity.FlowCode);

                    #endregion 2、增加一条提交审批记录
                }
                else if (entity.Status == 停复工申请状态.复工)
                {
                    if (projectInfo.PrjStatus == 项目状态.在建)
                        throw new BusinessException("当前项目已经是在建，不能重复申请");
                    Out(entity);
                }

                #region 附件

                var attachmentIds = projectAttachmentService.GetProjectAttachmentsByObjectIdAndType(entity.Id, 附件类型.停复工附件, 项目附件租户.LockOut).Select(a => a.Id);
                projectAttachmentService.Deleted(attachmentIds);

                foreach (var item in attachments)
                {
                    ProjectAttachment attachment = new()
                    {
                        Id = Guid.NewGuid().ToString().Replace("-", ""),
                        AttachmentId = item,
                        ObjectId = entity.Id.ToString(),
                        AttachmentType = 附件类型.停复工附件,
                        CreateTime = DateTime.Now,
                        Tenant = 项目附件租户.LockOut
                    };
                    projectAttachmentService.Create(attachment);
                }

                #endregion 附件

                applicationContext.Transaction.Complete();//提交事务
            }
            catch (BusinessException ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"停复工修改失败");
                throw new BusinessException(ex.Message);
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"停复工修改失败");
                throw new BusinessException("停复工修改失败");
            }
        }

        public void Update(ProjectLockOut entity)
        {
            projectLockOutRepository.Update(entity);
        }

        /// <summary>
        /// 复工
        /// </summary>
        /// <param name="entity"></param>
        public void Out(ProjectLockOut entity)
        {
            #region 1、将项目状态改为在建

            projectService.UpdateProjectStatus(entity.ProjectId, 项目状态.在建, entity.EndDate);

            #endregion 1、将项目状态改为在建

            #region 2、增加一条复工数据

            entity.EndDate = DateTime.Now.Date;
            entity.JobStatus = 1;
            entity.CreateTime = DateTime.Now.Date;
            entity.AuditType = 审核类型.已完结;
            projectLockOutRepository.Insert(entity);

            #endregion 2、增加一条复工数据
        }
    }
}